package com.btl.service.ai.auth;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.Serializable;
import java.nio.file.AccessDeniedException;
import java.util.Map;
import java.util.Objects;

/**
 * 认证拦截
 */
@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor, Serializable {

    public static String LOGIN_TOKEN_KEY = "loginToken"; //登录令牌键值

    @Value("${token.secret}")
    private String secret;

    @Resource
    private RedisTemplate<String, String> redisAuthTemplate;

    @Override
    public boolean preHandle(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler) throws AccessDeniedException {
        if (request.getRequestURI()
                .contains("/v3/api-docs")) {
            return true;
        }
        String loginToken = request.getHeader(LOGIN_TOKEN_KEY);
        if (Objects.isNull(loginToken)) {
            throw new AccessDeniedException("请先登录");
        }
        Claims claimsFromToken = getClaimsFromToken(loginToken);
        // 子账号id
        Long childId = claimsFromToken.get("userId", Long.class);
        String userKey = "login_tokens:mqtt:" + childId.toString();
        String authInfo;
        try {
            authInfo = redisAuthTemplate.opsForValue()
                    .get(userKey);
        } catch (Exception e) {
            throw new SecurityException("Invalid or expired authentication");
        }
        if (StringUtils.hasText(authInfo)) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                Map<String, Object> rs = objectMapper.readValue(authInfo, new TypeReference<Map<String, Object>>() {
                });
                // 会员用户id
                Long userId = Long.valueOf(rs.get("parentId")
                        .toString());
                String userSetMealType = rs.get("userSetMealType")
                        .toString();
                // 子账号名称
                String childName = rs.get("username")
                        .toString();
                // 登录id
                String loginId = rs.get("loginId")
                        .toString();
                ChildUser childUser = new ChildUser();
                childUser.setUserId(userId);
                childUser.setChildName(childName);
                childUser.setChildId(childId);
                SecurityContextHolder.set(childUser);
            } catch (JsonProcessingException e) {
                throw new AccessDeniedException("Invalid or expired authentication");
            }
            return true;
        } else {
            throw new AccessDeniedException("Invalid or expired authentication");
        }
    }

    @Override
    public void afterCompletion(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler, @Nonnull Exception ex) throws Exception {
        SecurityContextHolder.remove();
    }

    private Claims getClaimsFromToken(String token) throws AccessDeniedException {
        try {
            return Jwts.parser()
                    .setSigningKey(this.secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (JwtException e) {
            log.error("Error parsing JWT token: {}", e.getMessage());
            throw new AccessDeniedException("Invalid or expired authentication");
        }
    }

}
